# python学习 至此开始
# 学习日期: 2023/10/29 9:48
# 学习者: 任磊


# 导入所需的库
from socket import *
from gmssl import func, sm2, sm3
# from pysm4 import *
import string
import random
import tkinter as tk
from tkinter import messagebox
from PIL import ImageTk, Image
import threading
import os
import time
# from x3dh import *
# import SystemSign
import SystemVerify


# 创建所需要的类
# 创建密码库调用类
class Crypto_program(object):
    def __init__(self):
        super().__init__()

    # 创建所需要的方法
    # 定义生成国密SM2加解密体对象的方法
    @staticmethod
    def create_sm2_struct(puk, prk):
        sm2_crypto = sm2.CryptSM2(public_key=puk, private_key=prk)
        # 返回该SM2 对象
        return sm2_crypto

    # 创建数据可以直接进行SM3哈希的方法（此处直接输入 str型）
    @staticmethod
    def sm3_hash(data):
        # 进行数据类型的判断
        if type(data) is str:
            time_data = func.bytes_to_list(data.encode('utf-8'))
            hash_data = sm3.sm3_hash(time_data)
            # 返回输入值的hash值
            return hash_data
        else:
            pass

    # 随机生成对称密钥的方法(若输入非法，则默认输出 16 字节长度 sm4)
    @staticmethod
    def random_key_born(key_long):
        # 判断输入是否非法
        if type(key_long) == int:
            if int(key_long) > 0:
                pass
            else:
                key_long = - int(key_long)
        else:
            key_long = 16
        # 生成密钥
        words = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
        # 根据长度随机采样几个字符，得到一个列表
        chosen = random.sample(words, key_long)
        # 将列表的每个元素，拼接成一个大字符串
        # 赋值密钥
        end_key = "".join(chosen)
        # 返回随机生成的密钥
        return end_key

    # 定义调用生成随机SM2密钥对的方法
    @staticmethod
    def sm2_all_key_born():
        os.system("python E:\python练习\pythonProject\connectionSocket\国密SM2随机生成密钥文件.py")


# 创建中转通信类
class Connection_program(object):
    def __init__(self):
        super().__init__()

    work_flag = False  # 当前服务器开启状态标志
    Max_data = 4056  # 缓冲区大小
    PORT = 9000  # 端口号
    socket_listen_num = 10  # 监听数量
    alive_socket_num = 0  # 当前在线连接的客户端数量
    alive_socket_name_list = []  # 当前在线连接的客户端用户名列表
    client_state_list = []  # 用户状态列表  内容格式： 用户名1 状态数字1
    socket_listen_dict = {}  # 用于存储接收到的用户身份标志的字典，格式为：{用户身份公钥 : [挂载公钥状态(False, True)，在线状态(False, True)，通信状态(False, True),通信socket变量]}
    public_talk_list = []  # 用于存储用户双方的通信信息----------------------------------------------------测试数据
    public_talk_update = False  # 用于通信信息更新的判断
    public_talk_data_list = []  # 公用聊天数据列表
    public_talk_data_remove = []  # 移出公用聊天室的用户列表
    # client_max_try_login = 1  # 客户端最大可尝试登录次数  界面版已弃用
    client_hang_key_name_list = []  # 已挂载公钥的客户端用户名列表
    # 聊天室模式参数
    private_room_list = []  # 个人聊天室列表  保存 room 对象
    # 等待模式参数
    wait_mode_room_list = []  # 等待模式房间列表  保存 room 对象
    # 以下是界面所需参数
    # 监听列表框架
    connect_program_listen_list_text = ""

    # 设置通信所需的IP配置的函数
    @staticmethod
    def get_host_ip():
        s = socket(AF_INET, SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 80))  # 114.114.114.114也是dns地址
            ip = s.getsockname()[0]
        finally:
            s.close()
        return ip

    # 定义开启监听以及通用初始连接的方法  后接 未知模式  登录模式  注册模式
    @staticmethod
    def start_connect():
        # 创建监听文本栏以及绑定滚动条
        Connection_program.connect_program_listen_list_text = tk.Text(root_window, relief="raised", height=40, width=50, bd="3", padx=10, pady=10, font=("宋体", 10))
        Connection_program.connect_program_listen_list_text.grid(row=0, rowspan=2, column=2, padx=10, pady=10)
        """
        # 滚动条失效
        connect_program_listen_list_text_src = tk.Scrollbar(Connection_program.connect_program_listen_list_text)
        connect_program_listen_list_text_src.pack(side="right", fill="y")
        connect_program_listen_list_text_src.config(command=Connection_program.connect_program_listen_list_text.yview)
        Connection_program.connect_program_listen_list_text.config(yscrollcommand=connect_program_listen_list_text_src.set)
        """

        # print("服务端已成功启动中转通信的方法")
        Connection_program.connect_program_listen_list_text.insert("end", "服务端已成功启动中转通信的方法\n")
        # 通信部分
        IP = Connection_program.get_host_ip()  # 获得本机的IPV4地址
        PORT = Connection_program.PORT  # 设置端口号
        Max_data = Connection_program.Max_data  # 设置缓冲区大小
        # 设置网络层协议，传输层协议
        listenSocket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
        listenSocket.bind((IP, PORT))  # 绑定地址和端口
        Connection_program.work_flag = True
        # 设置并开启群发多线程
        th = threading.Thread(target=Connection_program.public_room_send_data)
        th.start()
        while Connection_program.work_flag:  # ------------------------------------------------------------------------------------ 持续处于监听状态
            # 判断当前用户数量
            while Connection_program.alive_socket_num < Connection_program.socket_listen_num:
                # 设置监听
                listenSocket.listen(Connection_program.socket_listen_num)  # 设置监听口
                # 接收连接对象的数据
                data_socket, addr = listenSocket.accept()
                # print("已连接到未知对象，正在进行身份验证...")
                Connection_program.connect_program_listen_list_text.insert("end", "已连接到未知对象，正在进行身份验证...\n")
                # 随机生成验证消息
                random_data = Crypto_program.random_key_born(16)
                data_socket.send(random_data.encode())
                # 接收对方的签名
                sign_random_data = data_socket.recv(Connection_program.Max_data).decode()
                if SystemVerify.system_verify_message(sign_random_data, random_data) is True:
                    data_socket.send("OK".encode())
                    # print("对方身份验证通过")
                    Connection_program.connect_program_listen_list_text.insert("end", "对方身份验证通过\n")
                    # 调用用户身份验证登录的方法
                    # print("正在判断客户端通信模式...")
                    Connection_program.connect_program_listen_list_text.insert("end", "正在判断客户端通信模式...\n")
                    connect_flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端的通信类型的消息
                    if connect_flag == "@sever_connect_mode1":  # 判断用户连接模式
                        # print("已判断客户端通信通信模式为:登录模式")
                        Connection_program.connect_program_listen_list_text.insert("end", "已判断客户端通信模式为：登录模式\n")
                        # print("正在进行登录身份验证...")
                        Connection_program.connect_program_listen_list_text.insert("end", "正在进行登录身份验证...\n")
                        next_flag = True
                        sign_flag, name = Connection_program.login_ensure_function(data_socket)  # 接收来自登录验证方法的返回数据
                    elif connect_flag == "@sever_connect_mode2":
                        # print("已判断客户端通信通信模式为:注册模式")
                        # print("正在进行注册服务...")
                        Connection_program.connect_program_listen_list_text.insert("end", "已判断客户端通信模式为：注册模式\n")
                        Connection_program.connect_program_listen_list_text.insert("end", "正在进行注册服务...\n")
                        sign_flag = False
                        name = None
                        next_flag = False
                        Connection_program.client_create(data_socket)
                    else:
                        # print("\033[91m 未知通信连接模式\033[0m")
                        Connection_program.connect_program_listen_list_text.insert("end", "未知通信连接模式\n")
                        sign_flag = False
                        name = None
                        next_flag = False
                    if next_flag is True:  # 判断是否进入多线程
                        if sign_flag is True:  # 判断是否通过登录
                            # print("该客户端登录验证通过")
                            Connection_program.connect_program_listen_list_text.insert("end", "该客户端登录验证通过\n")
                            # 已连接的客户端数量加 1
                            Connection_program.alive_socket_num += 1
                            # print("已连接到一位用户:{}，当前连接的用户数量为:{}".format(name, Connection_program.alive_socket_num))  # 测试数据 1
                            Connection_program.connect_program_listen_list_text.insert("end", "已连接到一位用户:{}, 当前连接的用户数量为：{}\n".format(name, Connection_program.alive_socket_num))
                            # 生成随机临时通信密钥
                            time_key = Crypto_program.random_key_born(16)
                            # 将此连接的客户端数据加入到监听列表中
                            Connection_program.alive_socket_name_list.append(name)  # 将该用户添加至在线用户列表中
                            Connection_program.update_client_state(name, 2)  # 修改该用户状态
                            # Connection_program.socket_listen_list.update({name: [False, True, False, data_socket, time_key]})  # 参数依次表示为： 公钥挂载状态，在线状态，通信状态，通信socket变量，通信密钥
                            # 启用多线程方法
                            th1 = threading.Thread(target=Connection_program.client_process_main, args=(data_socket, name, time_key))
                            # 启用该客户端的多线程
                            th1.start()
                        else:
                            # print("该客户端身份登录验证失败，已断开连接")
                            data_socket.close()
                            Connection_program.connect_program_listen_list_text.insert("end", "该客户端登录验证失败，已断开连接\n")
                    else:
                        data_socket.close()
                        # print("该客户端连接已结束")
                        Connection_program.connect_program_listen_list_text.insert("end", "该客户端连接已结束\n")
                else:
                    data_socket.send("false".encode())
                    data_socket.close()
                    # print("未知对象识别失败，已断开连接")
                    Connection_program.connect_program_listen_list_text.insert("end", "未知对象识别失败，已断开连接\n")
                if Main_program.work_flag is False:
                    break
        Connection_program.work_flag = False

    # 定义客户端进行用户注册的方法
    @staticmethod
    def client_create(data_socket):
        data_socket.send("OK".encode())  # 向客户端发送确认消息
        while True:
            client_name = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端发送的用户名
            if client_name in Main_program.client_name_data_list:  # 在已存在用户列表中搜索注册用户名是否已存在
                data_socket.send("False".encode())  # 判断确认消息
                pass_flag = False
            else:
                data_socket.send("OK".encode())
                pass_flag = True
            if pass_flag is True:
                client_password = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端发送的用户密码的哈希值
                # 调用用户文件增加的方法
                if File_program.update_client_list(client_name, client_password):  # 调用用户数据文件更新的方法，并判断返回结果
                    # 更新用户状态至展示列表
                    Connection_program.client_state_list.append(client_name)
                    Connection_program.client_state_list.append("1")
                    data_socket.send("OK".encode())  # 发送最终注册结果
                    # print("用户:{}，注册成功".format(client_name))
                    Connection_program.connect_program_listen_list_text.insert("end", "用户:{}，注册成功\n".format(client_name))
                    break
                else:
                    data_socket.send("False".encode())
            else:
                keep_flag = data_socket.recv(Connection_program.Max_data).decode()
                if keep_flag == "@sever_client_create_continue":
                    pass
                elif keep_flag == "@sever_client_create_exit":
                    Connection_program.connect_program_listen_list_text.insert("end", "客户端终止了注册\n")
                    break

    # 定义用于用户身份确定的方法
    @staticmethod
    def login_ensure_function(data_socket):
        # 验证结果标志
        find_flag = False  # 用户查找结果标志
        pass_flag = False  # 最终登录结果判断标志
        client_num = len(Main_program.client_name_data_list)  # 用户个数
        local_num = 0
        # 接收来自客户端的用户昵称
        name = data_socket.recv(Connection_program.Max_data).decode()
        # 遍历用户信息列表查找是否存在该用户
        for i_sign in range(0, client_num):
            if Main_program.client_name_data_list[i_sign] == name:
                data_socket.send("True".encode())  # 发送查找结果
                find_flag = True
                local_num = i_sign
                break
        if find_flag is True:
            # 接收来自客户端用户密码的哈希值
            hash_client = data_socket.recv(Connection_program.Max_data).decode()
            # 将接收到的结果与服务器中对应的数作比较, 以及判断用户是否重复登录
            if hash_client == Main_program.client_password_data_list[local_num] and name not in Connection_program.alive_socket_name_list:
                data_socket.send("True".encode())  # 发送登录通过消息
                pass_flag = True
            else:
                data_socket.send("False".encode())  # 发送登录未通过消息
        else:
            # 发送用户查找结果
            data_socket.send("False".encode())
        # 判断最终验证结果标志
        if pass_flag is True:  # 返回对应的验证值
            return True, name
        else:
            return False, None

    # 定义接收来自用户发送的信息的多线程方法  此为中转态 接收客户端的指令 然后调用对应的方法
    @staticmethod
    def client_process_main(data_socket, name, time_key):  # 包括参数: 通信结构体 用户名 通信密钥
        Connection_program.update_client_state(name, 2)  # 修改用户状态
        # 等待来自客户端的请求
        trans_data = data_socket.recv(Connection_program.Max_data).decode()
        # print("已接收到用户:{}的指令:{}".format(name, trans_data))
        Connection_program.connect_program_listen_list_text.insert("end", "已接收到用户:{}的指令:{}\n".format(name, trans_data))
        if trans_data == "@sever_public_chat_room_join":  # 客户端请求加入公共聊天室
            # 调用用户加入公用聊天室的方法
            Connection_program.client_into_public_room(data_socket, name, time_key)
        elif trans_data == "@sever_hang_key":  # 客户端请求挂载公钥
            # 调用用户挂载公钥的方法
            Connection_program.client_hang_connect_key(data_socket, name, time_key)
        elif trans_data == "@sever_get_key":  # 客户端请求获取公钥
            # 调用客户端查询挂载公钥的方法
            Connection_program.client_look_get_key(data_socket, name, time_key)
        elif trans_data == "@sever_private_room_mode_join":  # 客户端请求进入聊天室模式
            # 回复客户端接收请求
            data_socket.send("OK".encode())
            # 调用用户进入聊天室模式的方法
            Connection_program.client_private_room_mode_function(data_socket, name, time_key)
        elif trans_data == "@sever_wait_mode_join":  # 客户端请求进入等待模式
            # 调用用户进入等待模式的方法
            Connection_program.client_wait_mode_function(data_socket, name, time_key)
        elif trans_data == "@sever_connect_target_client":  # 客户端请求连接指定客户端
            # 调用用户连接指定用户的方法
            Connection_program.client_connect_target_client_function(data_socket, name, time_key)
        elif trans_data == "@sever_connect_end":  # 客户端即将离线
            Connection_program.update_client_state(name, 1)
            # print("用户：{}的连接已结束，当前剩余用户数量为：{}".format(name, Connection_program.alive_socket_num))
            Connection_program.connect_program_listen_list_text.insert("end", "用户：{}的连接已结束，当前剩余用户数量为：{}\n".format(name, Connection_program.alive_socket_num))
        elif trans_data == "@all_exception_error":  # 客户端出现异常
            Connection_program.update_client_state(name, 1)
            # print("\033[91m用户：{}的状态异常，连接已结束，当前剩余用户数量为：{}\033[0m".format(name, Connection_program.alive_socket_num))
            Connection_program.connect_program_listen_list_text.insert("end", "用户：{}的状态异常，连接已结束，当前剩余用户数量为：{}\n".format(name, Connection_program.alive_socket_num))
        else:
            # 调用用户数据处理的方法
            Connection_program.client_abnormal_exit_take(data_socket, name)

    # 定义用户加入公用聊天室的方法
    @staticmethod
    def client_into_public_room(data_socket, name, time_key):
        # 将用户数据加入到公用聊天室中
        Connection_program.socket_listen_dict.update({name: data_socket})
        # 为客户端发送确认消息
        data_socket.send("OK".encode())
        Connection_program.update_client_state(name, 4)
        # 持续接收客户端发送的消息
        while True:
            client_data = data_socket.recv(Connection_program.Max_data).decode()  # 接收客户端发送的数据
            if client_data == "@sever_public_chat_room_exit":  # 判断用户退出的指令
                # print("接收到用户：{}的指令：{}".format(name, client_data))
                Connection_program.connect_program_listen_list_text.insert("end", "接收到用户: {} 的指令:{}".format(name, client_data))
                data_socket.send("@client_public_chat_room_exit".encode())  # 返回通知客户端退出
                Connection_program.public_talk_data_remove.append(name)
                break
            else:
                Connection_program.public_talk_data_list.append(client_data)  # 存入公用聊天数据列表
        Connection_program.update_client_state(name, 2)
        # 调用用户菜单的方法
        Connection_program.client_process_main(data_socket, name, time_key)

    # 定义用户挂载用户公钥的方法
    @staticmethod
    def client_hang_connect_key(data_socket, name, time_key):
        sm2_public_key = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端的SM2公钥
        id_public_key = data_socket.recv(Connection_program.Max_data).decode()   # 接收来自客户端的身份公钥
        share_public_key = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端的预共享公钥
        share_public_key_sign = data_socket.recv(Connection_program.Max_data).decode()  # 接受来自客户端的预共享公钥的签名
        time_public_key_list = []
        while True:
            data_key = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自客户端的剩余数据
            if data_key == "@sever_key_end":  # 判断接收是否结束
                break
            else:
                time_public_key_list.append(data_key)  # 将一次性公钥加入列表中
        # 调用用户公钥数据文件生成的方法
        flag = File_program.create_client_key(name, sm2_public_key, id_public_key, share_public_key, share_public_key_sign, time_public_key_list)
        # 根据返回值返回给客户端回复
        if flag is True:
            data_socket.send("OK".encode())
            if name not in Connection_program.client_hang_key_name_list:  # 判断用户名不在已挂载公钥数据名列表中
                File_program.add_hang_key_client(name)  # 将用户添加至已挂载公钥用户文件中
                Connection_program.client_hang_key_name_list.append(name)  # 将已挂载公钥的用户名添加至已挂载公钥的用户列表中
        else:
            data_socket.send("False".encode())
        # 返回用户中转态的方法
        Connection_program.client_process_main(data_socket, name, time_key)

    # 定义用户查询，获取用户公钥的方法
    @staticmethod
    def client_look_get_key(data_socket, name, time_key):
        File_program.get_hang_key_client_list()  # 调用已挂载公钥用户数据列表的更新方法
        if len(Connection_program.client_hang_key_name_list) > 0:  # 判断当前已挂载公钥的客户端数量
            data_socket.send("OK".encode())  # 返回是否可发送消息的结果
            time.sleep(0.1)
            data_socket.send(str(len(Connection_program.client_hang_key_name_list)).encode())  # 向客户端发送当前已挂载公钥的用户数量
            pass_flag = True
        else:
            data_socket.send("False".encode())
            pass_flag = False
        if pass_flag is True:
            for hang_key_name in Connection_program.client_hang_key_name_list:  # 向客户端发送当前已挂载公钥的用户名称
                data_socket.send(hang_key_name.encode())
                time.sleep(0.2)  # 延迟，防止粘包
            data_socket.send("@client_name_end".encode())  # 发送结束提示
        # 接收来自客户端的下一步操作
        next_flag = data_socket.recv(Connection_program.Max_data).decode()
        if next_flag == "@sever_get_client_key":
            # print("接收到来自用户:{}的指令：{}".format(name, next_flag))
            choose_name = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自用户端发送的目标公钥用户名
            if choose_name in Connection_program.client_hang_key_name_list:  # 查询用户列表中的数据
                data_socket.send("OK".encode())  # 发送确认结果
                # 调用获得指定已挂载公钥用户的公钥数据的方法
                client_sm2_public_key, client_public_key, client_share_public_key, client_share_public_key_sign, client_time_public_key = File_program.get_client_hang_key(choose_name)  # 获得返回的用户公钥数据
                # 依次发送指定用户的公钥数据
                data_socket.send(client_sm2_public_key.encode())
                time.sleep(0.1)  # 延迟防止粘包
                data_socket.send(client_public_key.encode())
                time.sleep(0.1)  # 延迟，防止粘包
                data_socket.send(client_share_public_key.encode())
                time.sleep(0.1)  # 延迟，防止粘包
                data_socket.send(client_share_public_key_sign.encode())
                time.sleep(0.1)  # 延迟，防止粘包
                if client_time_public_key == "":   # 判断用户的一次性公钥是否存在
                    data_socket.send("NONE".encode())  # 发送用户的一次性公钥为空的提示
                else:
                    data_socket.send(client_time_public_key.encode())
        elif next_flag == "@sever_get_client_key_exit":
            # print("接收到来自用户:{}的指令：{}".format(name, next_flag))
            pass
        else:
            data_socket.close()
            #  print("\033[91m用户：{}连接异常,已中断连接\033[0m".format(name))
            exit()  # 停止该用户端的线程
        # 调用返回用户中转态的方法
        Connection_program.client_process_main(data_socket, name, time_key)

    # 定义服务端接收客户端请求进入聊天室模式的方法
    @staticmethod
    def client_private_room_mode_function(data_socket, name, time_key):
        # 接受客户客户端的下一个请求
        change_order = data_socket.recv(Connection_program.Max_data).decode()
        # 判断用户指令请求
        if change_order == "@sever_private_room_query":  # 查询聊天室
            # 聊天室查询
            Connection_program.private_room_guest_thread(data_socket, name, time_key)
        elif change_order == "@sever_private_room_create":  # 创建聊天室
            # 调用用户创建聊天室的方法
            Connection_program.private_room_host_thread(data_socket, name, time_key)
        elif change_order == "@sever_private_room_mode_exit":  # 退出聊天室模式
            # 返回，调用用户中转态的方法
            Connection_program.client_process_main(data_socket, name, time_key)
        else:
            # 调用客户端异常处理的方法
            Connection_program.client_abnormal_exit_take(data_socket, name)

    # 定义公共聊天室会话数据群发的方法
    @staticmethod
    def public_room_send_data():
        while True:
            if Connection_program.alive_socket_num > 0:  # 判断用户列表中非空
                if len(Connection_program.public_talk_data_remove) != 0:  # 判断移除用户列表非空
                    for remove_client in Connection_program.public_talk_data_remove:
                        for client in Connection_program.socket_listen_dict:
                            if remove_client == client:
                                Connection_program.socket_listen_dict.pop(client)  # 将该用户从聊天室中移除
                                Connection_program.public_talk_data_remove.remove(remove_client)  # 将该用户从移除列表中移除
                                break
                for data in Connection_program.public_talk_data_list:  # 遍历会话数据列表
                    send_data = data.encode()
                    Connection_program.public_talk_data_list.remove(data)  # 将该数据从列表中移除
                    for client in Connection_program.socket_listen_dict:  # 遍历公共聊天室逐个转发给聊天室中的客户
                        data_socket = Connection_program.socket_listen_dict[client]
                        data_socket.send(send_data)
            if Main_program.work_flag is False:  # 判断服务端是否执行关闭操作
                break
        print("群发多线程已结束")

    # 定义用户进入等待模式的方法   主动态
    @staticmethod
    def client_wait_mode_function(data_socket, name, time_key):
        data_socket.send("OK".encode())  # 回复客户端
        # 修改用户状态
        Connection_program.update_client_state(name, 3)
        # 创建房间
        room = Room_program(name)
        room.wait_mode_host_socket = data_socket
        room.wait_mode_flag = True
        # 将房间加入等待模式列表
        Connection_program.wait_mode_room_list.append(room)
        while True:
            talk_data = data_socket.recv(Connection_program.Max_data).decode()
            if talk_data == "@sever_wait_mode_exit":  # 判断用户是否退出等待模式
                Connection_program.wait_mode_room_list.remove(room)  # 从列表中移除该房间
                room.wait_mode_flag = False  # 改变用户等待状态标志，
                data_socket.send("@client_wait_mode_exit".encode())
                break
            else:
                pass
            if room.wait_mode_flag is True:  # 判断是否退出等待模式
                if room.wait_mode_guest_name != "":  # 判断是否有用户进入等待房间
                    if talk_data == "OK":  # 判断用户意愿
                        data_socket.send("OK".encode())
                        room.wait_mode_guest_socket.send("OK".encode())  # 回复对方用户请求结果
                        # 接收客户端用户的计算完成信号
                        test_data = data_socket.recv(Connection_program.Max_data).decode()
                        if test_data == "OK":  # 判断客户端计算信号
                            room.wait_mode_guest_socket.send("OK".encode())  # 向对方发送开始进行验证的信息信号
                            # 接收并转发客户端的解密结果
                            result_data = data_socket.recv(Connection_program.Max_data)
                            room.wait_mode_guest_socket.send(result_data)
                            # 接收客户端获得的验证消息
                            result_data = data_socket.recv(Connection_program.Max_data).decode()
                            if result_data == "OK":  # 判断服务端用户回复结果
                                while True:  # 正常加密通信部分
                                    talk_data = data_socket.recv(Connection_program.Max_data).decode()
                                    if talk_data == "@sever_wait_mode_active_this_connect_end":  # 判断客户端用户是否结束通信
                                        room.wait_mode_guest_socket.send("@client_wait_mode_passive_this_connect_end".encode())  # 通知对方通信结束
                                        data_socket.send("@client_wait_mode_active_this_connect_end".encode())
                                        break
                                    elif talk_data == "@sever_wait_mode_passive_this_connect_end":
                                        break
                                    else:
                                        room.wait_mode_guest_socket.send(talk_data.encode())
                            else:
                                pass
                        else:
                            room.wait_mode_guest_socket.send("NO".encode())
                    else:
                        data_socket.send("OK".encode())
                        room.wait_mode_guest_socket.send("NO".encode())
                    # 移除对方用户在房间内的数据
                    room.wait_mode_guest_socket = ""
                    room.wait_mode_guest_name = ""
            else:
                break
        # 修改用户状态
        Connection_program.update_client_state(name, 2)
        # 返回调用用户中转态的方法
        Connection_program.client_process_main(data_socket, name, time_key)

    """
    # 弃案
    # 定义等待模式房间线程的创建方法
    @staticmethod
    def wait_room_thread_function(room):
        while True:
            next_flag = False
            while True:
                if room.wait_mode_other_name != "":
                    break
            if room.wait_mode_self_talk_data == "YES":
                room.wait_mode_other_socket.send("OK".encode())
                next_flag = False
            else:
                room.wait_mode_other_socket.send("FALSE".encode())
            if next_flag is True:  # 判断是否执行后续的 X3DH 协议
                # 接收对方使用的一次性公钥
                my_time_public_key = room.wait_mode_other_socket.recv(Connection_program.Max_data).decode()
                # 接收对方对应使用的一次性公钥
                other_time_public_key = room.wait_mode_other_socket.recv(Connection_program.Max_data).decode()
                # 转发获得消息
                room.wait_mode_self_socket.send(my_time_public_key.encode())
                time.sleep(0.1)  # 时延防止粘包
                room.wait_mode_self_socket.send(other_time_public_key.encode())
                # 接收判断结果
                pass_flag = room.wait_mode_self_socket.recv(Connection_program.Max_data).decode()
                if pass_flag == "OK":  # 判断用户的判断结果
                    room.wait_mode_other_socket.send("OK".encode())
                else:  # 用户未能识别，将该用户移除等待房间
                    room.wait_mode_other_socket.send("False".encode())
                    # 置空等待模式数据
                    room.wait_mode_other_name = ""
                    room.wait_mode_other_socket = ""
                    room.wait_mode_other_talk_data = ""

    """

    # 定义客户端通信连接用户端指定用户的方法  (对应等待模式  被动态)
    @staticmethod
    def client_connect_target_client_function(data_socket, name, time_key):
        next_flag = False
        target_room = ''
        data_socket.send("OK".encode())  # 回复客户端
        # 接收客户端发送的指定客户端的用户名
        target_name = data_socket.recv(Connection_program.Max_data).decode()
        for room in Connection_program.wait_mode_room_list:  # 判断目标用户是否在等待列表中
            if room.name == target_name:
                target_room = room
                next_flag = True
                break
        if next_flag is True:  # 判断客户端用户发送的用户是否在等待状态
            if target_room.wait_mode_guest_name == "":  # 判断当前是否可以加入
                data_socket.send("OK".encode())  # 向客户端用户回复结果
                Connection_program.update_client_state(name, 3)  # 修改用户状态
                # 将用户自己的数据加入房间中
                target_room.wait_mode_guest_socket = data_socket
                target_room.wait_mode_guest_name = name
                # 向对方发送提示消息  己方用户名
                target_room.wait_mode_host_socket.send(name.encode())  # 发送提示消息
                # 判断来自客户端用户接受对方回复的结果
                flag = data_socket.recv(Connection_program.Max_data).decode()
                if flag == "OK":  # 判断回复结果
                    # 开始进行 X3DH 协议下的通信连接
                    # 接收并转发使用对方的一次性公钥
                    x3dh_data = data_socket.recv(Connection_program.Max_data)
                    target_room.wait_mode_host_socket.send(x3dh_data)
                    # 接收并转发自己的身份公钥
                    x3dh_data = data_socket.recv(Connection_program.Max_data)
                    target_room.wait_mode_host_socket.send(x3dh_data)
                    # 接收并转发自己使用的临时公钥
                    x3dh_data = data_socket.recv(Connection_program.Max_data)
                    target_room.wait_mode_host_socket.send(x3dh_data)
                    # 接收客户端接收到的计算完成信号
                    talk_data = data_socket.recv(Connection_program.Max_data).decode()
                    if talk_data == "OK":
                        # 接收并转发验证判断消息
                        test_data = data_socket.recv(Connection_program.Max_data)
                        target_room.wait_mode_host_socket.send(test_data)
                        # 接收并转发我方的验证结果
                        test_data = data_socket.recv(Connection_program.Max_data).decode()
                        if test_data == "OK":
                            target_room.wait_mode_host_socket.send("OK".encode())
                            while True:
                                talk_data = data_socket.recv(Connection_program.Max_data).decode()
                                if talk_data == "@sever_wait_mode_active_this_connect_end":  # 判断客户端是否为主动中断通信
                                    data_socket.send("@client_wait_mode_active_this_connect_end".encode())
                                    target_room.wait_mode_host_socket.send("@client_wait_mode_passive_this_connect_end".encode())
                                    break
                                elif talk_data == "@sever_wait_mode_passive_this_connect_end":  # 判断客户端是否为被动中断通信
                                    break
                                else:
                                    target_room.wait_mode_host_socket.send(talk_data.encode())
                        else:
                            target_room.wait_mode_host_socket.send("NO".encode())
                    else:
                        pass
                else:
                    pass
            else:
                data_socket.send("NO".encode())
        else:
            data_socket.send("NO".encode())
        # 返回调用用户中转态的方法
        Connection_program.client_process_main(data_socket, name, time_key)

    # 定义创建用户私人聊天室的方法  房主态线程
    @staticmethod
    def private_room_host_thread(data_socket, name, time_key):
        data_socket.send("OK".encode())  # 回复客户端
        # 创建房间对象
        room = Room_program(name)
        room.host_socket = data_socket
        # 接收用户端发送的创建房间的参数
        max_person_num = data_socket.recv(Connection_program.Max_data).decode()  # 房间最大容纳人数参数
        if max_person_num != "NONE":
            room.max_person_num = int(max_person_num)
        room_password = data_socket.recv(Connection_program.Max_data).decode()  # 房间的口令
        if room_password != "NONE":
            room.password = room_password
        room.member_name_list.append(name)  # 房间的成员列表
        room.member_socket_list.append(data_socket)  # 房间的成员通信体列表
        # 将房间对象加入到房间列表中
        Connection_program.private_room_list.append(room)
        # 启用房间多线程
        room_th = threading.Thread(target=Connection_program.private_room_data_send_thread, args=(room, ))
        room_th.start()
        # 向服务端发送房间创建完成的信号
        data_socket.send("OK".encode())
        while True:
            talk_data = data_socket.recv(Connection_program.Max_data).decode()
            if talk_data == "@sever_private_room_exit":  # 判断退出及关闭房间线程
                room.work_flag = False  # 更改聊天室工作状态
                Connection_program.private_room_list.remove(room)  # 从聊天室列表中移除该房间
                time.sleep(1)  # 设置时延，以保证房间中所有用户已退出房间，以及房间线程结束
                room.__del__()  # 销毁房间
                break
            else:
                room.talk_data_list.append(talk_data)
        # 返回调用聊天模式
        Connection_program.client_private_room_mode_function(data_socket, name, time_key)

    # 定义用户进入私人聊天室的方法  成员态线程
    @staticmethod
    def private_room_guest_thread(data_socket, name,  time_key):
        next_flag = False
        target_room = ""
        data_socket.send("OK".encode())  # 回复客户端
        # 遍历查询当前聊天室列表
        room_free_name_list = []
        room_password_list = []
        if len(Connection_program.private_room_list) != 0:  # 判断当前是否存在聊天室
            for room in Connection_program.private_room_list:
                data_socket.send(room.name.encode())  # 发送房主名
                time.sleep(0.1)  # 时延，防止粘包
                data_socket.send(str(room.now_person_num).encode())  # 发送当前房间的人数
                time.sleep(0.1)
                data_socket.send(str(room.max_person_num).encode())  # 发送当前房间的最大容纳人数
                time.sleep(0.1)
                if room.password == "NONE":  # 判断房间是否加密
                    data_socket.send("NO".encode())
                else:
                    data_socket.send("YES".encode())
                if int(room.max_person_num) - int(room.now_person_num) > 0:  # 判断当前房间是否有空余
                    room_free_name_list.append(room.name)
                    room_password_list.append(room.password)
        data_socket.send("@all_data_end".encode())  # 发送信息结束提示
        change_flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收客户端的下一个操作指令
        if change_flag == "@sever_private_room_join_target":  # 判断是否加入聊天室
            choose_name = data_socket.recv(Connection_program.Max_data).decode()  # 接收客户端发送的房主名
            client_password = data_socket.recv(Connection_program.Max_data).decode()
            if choose_name in room_free_name_list:
                for room in Connection_program.private_room_list:
                    if choose_name == room.name:
                        target_room = room
                        break
                if target_room.password == client_password:
                    next_flag = True
                if next_flag is True:  # 判断是否进入聊天室
                    Connection_program.update_client_state(name, 4)
                    target_room.member_socket_list.append(data_socket)  # 将用户通信体加入房间中
                    target_room.member_name_list.append(name)  # 将用户名加入列表中
                    data_socket.send("OK".encode())  # 回复客户端加入房间的结果
                    target_room.talk_data_list.append("{} 加入了聊天室".format(name))
                    target_room.host_socket.send(("@client_private_chat_mode_append_member:" + name).encode())  # 向房主发送提示信息
                    target_room.now_person_num += 1
                    while True:
                        talk_data = data_socket.recv(Connection_program.Max_data).decode()
                        if target_room in Connection_program.private_room_list:
                            if talk_data != "@sever_private_room_active_exit":  # 判断客户端是否退出聊天室
                                if talk_data != "@sever_private_room_passive_exit":
                                    target_room.talk_data_list.append(talk_data)
                                else:
                                    break
                            else:
                                target_room.talk_data_list.append("{} 已退出聊天室".format(name))
                                target_room.host_socket.send(("@client_private_chat_mode_remove_member:" + name).encode())  # 向房主发送提示信息
                                target_room.member_socket_list.remove(data_socket)  # 将用户的通信体从房间中移除
                                data_socket.send("@client_private_room_exit".encode())
                                target_room.now_person_num -= 1
                                target_room.member_name_list.remove(name)
                                break
                        else:
                            break
                    Connection_program.update_client_state(name, 2)
                else:
                    data_socket.send("FALSE".encode())
            else:
                data_socket.send("FALSE".encode())
        elif change_flag == "@sever_private_room_not_join":
            pass
        # 返回调用用户聊天室模式的方法
        Connection_program.client_private_room_mode_function(data_socket, name, time_key)

    # 定义用于个人聊天室中转消息的方法  房间线程
    @staticmethod
    def private_room_data_send_thread(room):
        Connection_program.update_client_state(room.name, 4)  # 改变用户状态
        while True:
            for talk_data in room.talk_data_list:
                for member_socket in room.member_socket_list:
                    member_socket.send(talk_data.encode())
                room.talk_data_list.remove(talk_data)
            if room.work_flag is False:  # 判断关闭聊天室的标志
                for member_socket in room.member_socket_list:
                    member_socket.send("@client_private_room_destroy".encode())  # 通知客户端，房间即将被房主撤销
                break
        Connection_program.update_client_state(room.name, 2)  # 改变用户状态

    # 定义客户端用户异常退出的方法
    @staticmethod
    def client_abnormal_exit_take(data_socket, name):
        Connection_program.connect_program_listen_list_text.insert("end", "用户:{}连接异常中断！\n".format(name))
        # print("用户:{}连接异常中断".format(name))
        # 调用用户状态修改的方法
        if Connection_program.update_client_state(name, 1):
            data_socket.close()
            # print("已成功处理用户 {} 的异常中断".format(name))
            Connection_program.connect_program_listen_list_text.insert("end", "已成功处理用户：{} 的异常中断！".format(name))
        else:
            # print("\033[91m处理用户 {} 异常中断失败！\0330m".format(name))
            Connection_program.connect_program_listen_list_text.insert("end", "处理用户：{} y异常中断失败！".format(name))

    # 定义改变用户状态的方法
    """
    1 离线模式  1  ： 即存在该用户，但该用户不在线
    2 在线模式  2  ： 存在该用户，且该用户在线，但不能进行通信连接请求
    3 等待模式  3  ： 存在该用户，并且用户在线，可以进行通信连接请求
    4 繁忙模式  4  ： 存在该用户，且该用户在线，但该用户正处于通信中，即同样无法进行通信连接请求
    """
    @staticmethod
    def update_client_state(name, mode):  # 参数分别为  用户名  修改模式(1 离线，2 在线，3 等待，4 繁忙)
        if name in Connection_program.client_state_list:
            if mode in [1, 2, 3, 4]:
                num = len(Connection_program.client_state_list)
                for i in range(0, num):
                    if name == Connection_program.client_state_list[i]:
                        Connection_program.client_state_list[i + 1] = mode
                        if mode == 1:
                            Connection_program.alive_socket_num -= 1
                            Connection_program.alive_socket_name_list.remove(name)
                        return True  # 返回修改结果
            else:
                return True
        else:
            return False


# 创建聊天室房间类
class Room_program(object):
    def __init__(self, name):
        self.name = name  # 房主名
        self.host_socket = ""  # 房主独有的
        # 聊天室模式
        self.now_person_num = 1  # 房间当前的人数  初始创建默认为 1
        self.max_person_num = 5  # 房间的最大容纳人数  默认为 5
        self.password = "NONE"  # 房间的进入口令， 默认为 NONE，即任意用户皆可进入
        self.member_name_list = []  # 成员名列表
        self.member_socket_list = []  # 成员通信体列表
        self.talk_data_list = []  # 聊天数据列表
        self.work_flag = True  # 工作状态标志，用于房间线程判断是否结束结束
        # 等待模式
        self.wait_mode_flag = False  # 等待模式状态标志
        self.wait_mode_host_socket = ""  # 等待模式用户自己的通信体
        self.wait_mode_guest_name = ""  # 等待模式其他用户名
        self.wait_mode_guest_socket = ""  # 等待模式其他用户通信体
        self.wait_mode_talk_data_list = []  # 等待模式用户的会话列表

    def __del__(self):  # 删除对象的方法
        return True


# 创建文件处理类
class File_program(object):
    def __init__(self):
        super().__init__()

    # 创建用户公钥数据文件的方法
    @staticmethod
    def create_client_key(name, client_sm2_public_key, client_public_key, client_share_public_key, client_share_public_key_sign, client_time_share_public_key_list):  # 参数依次为：用户名称，用户身份公钥，用户预共享公钥，用户预共享公钥的签名数据，用户一次性预共享公钥列表
        client_file_name = "sever(3.50)" + str(name) + ".txt"  # 组合生成用户目标文件
        client_file = open(client_file_name, "w+")  # 创建用户公钥文件  重写
        client_file.write(client_sm2_public_key + "\n")  # 写入用户SM2公钥
        client_file.write(client_public_key + "\n")  # 写入用户公钥
        client_file.write(client_share_public_key + "\n")  # 写入用户预共享公钥
        client_file.write(client_share_public_key_sign + "\n")  # 写入用户预共享公钥的签名
        for key in client_time_share_public_key_list:  # 遍历一次性公钥列表，写入文件
            client_file.write(key + "\n")
        client_file.close()
        return True

    # 定义添加已挂载公钥的用户至相关列表文件的方法
    @staticmethod
    def add_hang_key_client(name):
        hang_key_client_file = open("sever(3.50)_hang_key_client_list.txt", "a+")
        client_data = hang_key_client_file.read()
        if name in client_data:
            pass
        else:
            hang_key_client_file.write(name + "\n")
        hang_key_client_file.close()

    # 定义更新已挂载公钥的用户数据列表的方法
    @staticmethod
    def get_hang_key_client_list():
        # 清空已有的用户列表，防止用户数据重复
        Connection_program.client_hang_key_name_list.clear()
        hang_key_client_file = open("sever(3.50)_hang_key_client_list.txt", "r")
        for data in hang_key_client_file.readlines():
            Connection_program.client_hang_key_name_list.append(data.strip("\n"))
        hang_key_client_file.close()

    # 定义获取指定已挂载公钥用户的公钥数据, 以及将一次性公钥减去一个的方法
    @staticmethod
    def get_client_hang_key(name):
        client_file_name = "sever(3.50)" + str(name) + ".txt"
        client_file = open(client_file_name, "r")
        client_key_list = client_file.readlines()
        client_file.close()
        client_sm2_public_key = client_key_list[0].strip("\n")  # 获得用户SM2公钥
        client_public_key = client_key_list[1].strip("\n")  # 获得用户身份公钥
        client_share_public_key = client_key_list[2].strip("\n")  # 获得用户预共享公钥
        client_share_public_key_sign = client_key_list[3].strip("\n")  # 获得用户预共享公钥的签名
        client_time_public_key_list = []
        for key in client_key_list[4:]:  # 获得用户余下的一次性公钥
            client_time_public_key_list.append(key.strip("\n"))
        client_time_public_key = client_time_public_key_list[0]  # 获得用户的一个一次性共享公钥
        client_time_public_key_list.remove(client_time_public_key)  # 从临时一次性公钥列表中移除该公钥
        client_file = open(client_file_name, "w")  # 打开用户公钥数据文件重写
        client_file.write(client_sm2_public_key + "\n")
        client_file.write(client_public_key + "\n")
        client_file.write(client_share_public_key + "\n")
        client_file.write(client_share_public_key_sign + "\n")
        for key in client_time_public_key_list:
            client_file.write(key + "\n")
        client_file.close()
        return client_sm2_public_key, client_public_key, client_share_public_key, client_share_public_key_sign, client_time_public_key  # 返回所需的用户公钥数据

    # 定义客户端从客户数据库中获得用户数据的方法
    @staticmethod
    def init_client_list():
        Main_program.client_name_data_list.clear()
        Main_program.client_password_data_list.clear()
        if os.path.exists(Main_program.client_data_list_file_name):  # 判断用户数据文件是否存在
            client_data_list_file = open(Main_program.client_data_list_file_name, "r")
            client_content_list = client_data_list_file.readlines()
            client_data_list_file.close()
            client_num = len(client_content_list)
            for i in range(0, client_num):
                if i % 3 == 0:
                    Main_program.client_name_data_list.append(client_content_list[i].strip("\n"))
                    Connection_program.client_state_list.append(client_content_list[i].strip("\n"))
                    Connection_program.client_state_list.append(1)
                elif i % 3 == 1:
                    Main_program.client_password_data_list.append(client_content_list[i].strip("\n"))
            # 同时初始化获得公钥挂载状况
            File_program.get_hang_key_client_list()
            return True  # 返回读取结果
        else:
            return False

    # 定义更新用户数据文件的方法
    @staticmethod
    def update_client_list(name, password):
        pass_flag = True
        for item in Main_program.client_name_data_list:
            if item == name:  # 判断用户名是否重复
                pass_flag = False
                break
        if pass_flag is True:
            client_data_file = open(Main_program.client_data_list_file_name, "a")  # 以追加模式打开用户数据文件
            # 写入新增的用户数据
            client_data_file.write(name + "\n")
            client_data_file.write(password + "\n")
            client_data_file.write("@file_should_division\n")
            client_data_file.close()
            # 将新增的用户数据同时添加入临时用户数据表中
            Connection_program.client_state_list.append(name)
            Connection_program.client_state_list.append(1)
            Main_program.client_name_data_list.append(name)
            Main_program.client_password_data_list.append(password)
            return True
        else:
            return False


# 创建图形界面类
class Window_program(object):
    def __init__(self):
        super().__init__()

    # 以下为窗口的相关参数
    screen_size = "1000x650+200+100"
    name = "基于X3DH的开发测试程序(服务端) v3.50"

    # 创建工具栏的方法
    @staticmethod
    def create_menu():
        # 创建工具栏
        root_menu = tk.Menu(root_window, )
        root_window.config(menu=root_menu)
        root_menu.add_command(label="帮助", command=Window_program.help_function)
        root_menu.add_command(label="关于", command=Window_program.about_function)
        root_menu.add_command(label="其他", command=Window_program.other_function)

    # 以下均为实现工具栏中的方法
    @staticmethod
    def help_function():
        messagebox.showinfo("帮助", "此版本仅仅完成了基本功能，若遇到以下问题: \n 1 退出按键失效：使用任务管理器将其关闭 \n 2 通信失败；请确保通信双方使用同一对系统 \n 3 界面划分：左侧为用户状态展示列表，每 {} 秒刷新一次，右侧为连接情况及收到客户端的指令展示列表 \n 4 启动失败：请确保用户基础数据文件及挂载公钥数据文件是否存在！".format(Main_program.show_time))

    @staticmethod
    def about_function():
        messagebox.showinfo("关于", "这是基于X3DH协议的加密通信系统(服务端) v3.50 \n 作者: 信安21-1 任磊 \n 完成日期: 2023-10-29")

    @staticmethod
    def other_function():
        messagebox.showinfo("其他", "本服务端系统在点击关闭按钮后，尚且无法彻底关闭，根据作者测试还剩下监听线程未关闭，需手动强行关闭")

    @staticmethod
    def show_sever_close_false():
        messagebox.showwarning("警告", "当前仍存在与服务端连接的客户端，现在无法关闭！")

    @staticmethod
    def deny_exit():
        messagebox.showwarning("警告", "您不能从此处关闭服务端！", )

    # 定义导入图片并调整图片尺寸的方法
    @staticmethod
    def get_img(file, flag, width, height):
        if flag is True:  # 判断是否需要改变图像尺寸
            img = Image.open(file).resize((width, height))
        else:
            img = Image.open(file)
        return ImageTk.PhotoImage(img)


# 创建主程序
class Main_program(object):
    def __init__(self):
        super().__init__()

    work_flag = False  # 服务端是否处于工作状态的唯一标志
    version = "3.50"  # 系统版本信息
    client_name_data_list = []  # 用户名列表
    client_password_data_list = []  # 用户口令哈希值列表
    client_data_list_file_name = "sever(3.50)_client_basic_data_list.txt"  # 用户数据文件名 用于读取用户数据
    show_time = 1  # 用户状态展示刷新时间间隔

    # 定义启动服务端程序的方法
    @staticmethod
    def start_work():
        print("这是基于X3DH协议下的服务端，当前版本为:{}".format(Main_program.version))
        if File_program.init_client_list():  # 判断获取用户数据返回结果
            print("用户数据获取成功，服务器启动成功")
            # 改变工作状态
            Main_program.work_flag = True
            # 创建开启通信的线程方法
            start_listen_th = threading.Thread(target=Connection_program.start_connect)
            start_listen_th.start()
            # 调用用户状态刷新展示的方法
            show_client_state_th = threading.Thread(target=Main_program.show_client_state_function)
            show_client_state_th.start()
        else:
            print("\033[91m用户数据获取失败，服务器启动失败\033[0m")

    # 定义定期展示用户状态的方法  用户状态列表栏
    @staticmethod
    def show_client_state_function():
        # 创建展示用户状态栏文本框以及绑定滚动条
        client_state_text = tk.Text(root_window, relief="raised", bd="3", width=20, height=25, fg="blue", padx=10, pady=20, font=("宋体", 15))
        """
        # 滚动条部分失效
        client_state_text_src = tk.Scrollbar(client_state_text, width=15)
        client_state_text_src.pack(side="right", fill="y")
        client_state_text_src.config(command=client_state_text.yview)
        client_state_text.config(yscrollcommand=client_state_text_src.set)
        """
        client_state_text.grid(column=0, row=0, rowspan=2, padx=10, pady=10)
        # 服务端界面提示文本
        tk.Label(root_window, text="基于X3DH的开发测试程序\n服务端实时监控面板v3.50", font=("kaiti", 18), anchor="center", bd=3).grid(row=0, column=1, padx=10, pady=10)
        # 创建用户公钥挂载状况展示栏
        client_hang_key_text = tk.Text(root_window, relief="raised", bd="3", height=20, width=30, fg="blue", padx=10, pady=20, font=("宋体", 15))
        client_hang_key_text.grid(row=1, column=1, padx=10, pady=10)
        # 设置服务端的关闭按钮
        tk.Button(root_window, text="关闭服务端", fg="red", font=("宋体", 18), anchor="center", command=Main_program.close_work, relief="raised").grid(row=2, column=1, padx=10, pady=5)
        # 刷新展示用户状态， 以及公钥的部分
        client_num = len(Connection_program.client_state_list)
        while True:
            # 用户状态刷新
            client_state_data = "用户状态列表\n\n"
            client_state_text.delete("1.0", "end")  # 清空状态列表
            client_hang_key_text.delete("1.0", "end")
            for i in range(0, client_num, 2):
                # print("用户:{}，状态:{}".format(Connection_program.client_state_list[i], Connection_program.client_state_list[i + 1]))
                client_state_data += "用户:{}，状态:{}".format(Connection_program.client_state_list[i], Connection_program.client_state_list[i + 1]) + "\n"
            client_state_text.insert("end", client_state_data)
            # 用户公钥挂载状态刷新
            client_hang_key_data = "公钥挂载状态列表\n\n"
            for name in Connection_program.client_hang_key_name_list:
                client_hang_key_data += str(name) + "\n"
            client_hang_key_text.insert("end", client_hang_key_data)
            time.sleep(Main_program.show_time)
            if Main_program.work_flag is False:
                break
        print("用户展示线程已结束")

    # 定义关闭客户端的方法  实际上未能完全实现 仍有部分线程需要手动关闭
    @staticmethod
    def close_work():
        if Connection_program.alive_socket_num == 0:
            Main_program.work_flag = False
            print("客户端已关闭！")
            root_window.destroy()
            exit()
        else:
            Window_program.show_sever_close_false()
            print("当前仍有用户连接中，无法关闭客户端！")


# 创建根窗口
root_window = tk.Tk()
root_window.title(Window_program.name)  # 设置窗口名称
root_window.geometry(Window_program.screen_size)  # 设置窗口大小
root_window.config(background="azure")  # 设置背景颜色
root_window.attributes("-topmost", 1)
Window_program.create_menu()  # 创建根界面工具栏
root_window.resizable(False, False)  # 设置使窗口大小不可变
root_window.protocol("WM_DELETE_WINDOW", Window_program.deny_exit)  # 设置限制，防止服务端非法退出运行


# 启动服务端程序
Main_program.start_work()


root_window.mainloop()  # 刷新窗口
